<template>
  <div class="main-container">
    <!-- 条件搜索 -->
    <Condition>
      <!-- 算法名称 -->
      <div class="condition-item">
        <span class="condition-label">算法名称</span>
        <el-input 
          class="condition-input" 
          v-model="conditionForm.name" 
          placeholder="请输入算法名称"
          @keyup.enter.native="getList"
          @change="getList" 
        />
      </div>
      <!-- 算法平台 -->
      <div class="condition-item">
        <span class="condition-label">算法平台</span>
        <el-select 
          class="condition-input" 
          v-model="conditionForm.system" 
          placeholder="请选择算法平台"
          clearable
          @change="getList"
        >
          <el-option v-for="(item, index) in systems" :key="index" :label="item.name" :value="item.id" />
        </el-select>
      </div>
      <div class="condition-item">
        <span class="condition-label">状态</span>
        <el-select 
          class="condition-input" 
          v-model="conditionForm.status" 
          placeholder="请选择算法平台"
          clearable
          @change="getList"
        >
          <el-option v-for="(item, index) in taskStatus" :key="index" :label="item.label" :value="item.value" />
        </el-select>
      </div>
    </Condition>
    <!-- 数据表格部分 -->
    <div class="data-show">
      <!-- 头部操作按钮部分 -->
      <div class="data-actions">
        <span class="aniTxtBtn action" @click="linkToCreate">新增算法</span>
      </div>
      <!-- 底下表格 -->
      <div class="data-table">
        <el-table border v-loading="conditionForm.loading" :data="datas" stripe show-header>
          <el-table-column label="序号" align="center" type="index" show-overflow-tooltip width="100" />
          <el-table-column label="id" width="160" align="center" prop="id">
            <template #default="{ row }">
              <el-tooltip content="查看日志" placement="top">
                <el-button class="text-btn" link @click="showLog(row)">{{ row.id }}</el-button>
              </el-tooltip>
            </template>
          </el-table-column>
          <el-table-column label="名称" align="center" prop="name">
            <template #default="{ row }">
              <el-tooltip :disabled="!row.optSelect || (Array.isArray(row.optSelect) && row.optSelect.length === 0)" content="查看生成步骤" placement="top">
                <el-button class="text-btn" link @click="showSelect(row)">{{ row.name }}</el-button>
              </el-tooltip>
            </template>
          </el-table-column>
          <el-table-column label="创建人" align="center" prop="createBy"  />
          <el-table-column label="创建时间" align="center" show-overflow-tooltip prop="createTime" />
          <el-table-column label="平台" align="center" show-overflow-tooltip prop="system">
            <template #default="{row}">
              {{ getShow(row.system, 'id', systems, 'name') }}
            </template>
          </el-table-column>
          <el-table-column label="算法描述" align="center" show-overflow-tooltip prop="description">
            <template #default="{row}">
              {{ row.description ? row.description : '--' }}
            </template>
          </el-table-column>
          <el-table-column label="状态" align="center" show-overflow-tooltip prop="status">
            <template #default="{row}">
              {{ getShow(row.status, 'value', taskStatus, 'label') }}
            </template>
          </el-table-column>
          <el-table-column label="投入使用" align="center" prop="isUsed">
            <template #default="{row}">
              <el-switch v-model="row.isUsed" :active-value="1" :inactive-value="0" inline-prompt active-text="是" inactive-text="否" @change="changeIsUsed(row, $event)" />
            </template>
          </el-table-column>
          <el-table-column label="操作" align="center" width="300" fit>
            <template #default="scope">
              <div class="table-actions table-actions-column">
                <div class="actions-column">
                  <button :disabled="downloadDisabled(scope.row, 'staticLinkFileId')" class="aniTxtBtn main-color" @click="downloadRes(scope.row, 'staticLinkFileId')">静态文件</button>
                  <button :disabled="downloadDisabled(scope.row, 'dynamicLinkFileId')" class="aniTxtBtn main-color" @click="downloadRes(scope.row, 'dynamicLinkFileId')">动态文件</button>
                  <button :disabled="downloadDisabled(scope.row, 'execResultFileId')" class="aniTxtBtn main-color" @click="downloadRes(scope.row, 'execResultFileId')">执行文件</button>
                </div>
                <div class="actions-column">
                  <button  :disabled="startDisabled(scope.row.status)" class="aniTxtBtn blue" @click="exec(scope.row)">启动</button>
                  <button  :disabled="restartDisabled(scope.row.status)" class="aniTxtBtn blue" @click="restart(scope.row)">重启</button>
                  <button class="aniTxtBtn red" @click="delItem(scope.row)">删除</button>
                </div>     
              </div>
            </template>
          </el-table-column>
          <!-- 没有数据时显示 -->
          <template #empty>
            <i class="iconfont icon-wushuju1 data-empty-icon"></i>
            <h3 class="data-empty">暂无数据</h3>
          </template>
        </el-table>
      </div>
      <Pagination 
        v-show="conditionForm.totalRow > 0" 
        :total="conditionForm.totalRow"
        v-model:page="conditionForm.pageNumber"
        v-model:limit="conditionForm.pageSize"
        @pagination="pageChange" 
      />
    </div>
    <Dialoger
      :title="`算法日志-${log.logName} (${log.logId})`"
      :visible="log.flag"
      @confirm="handleCloseLog"
      @cancel="handleCloseLog"
    >
      <div class="log-container" v-if="log.logs.length > 0">
        <div class="log-item" v-for="(item, index) in log.logs" :key="index">
          <!-- {{ item.lineNumber }} {{ item.lineText }} -->
          <span class="log-item-num">{{ item.lineNumber }}</span>
          <p class="log-item-content">{{ item.lineText }}</p>
        </div>
      </div>
      <div class="log-empty" v-else>
        <i class="iconfont icon-wushuju1 data-empty-icon"></i>
        <h3 class="data-empty">暂无数据</h3>
      </div>  
    </Dialoger>
    <!-- 查看算法步骤弹框 -->
    <Dialoger
      width="30%"
      :title="`生成步骤-${optSelectDialog.dialogName} (${optSelectDialog.dialogId})`"
      :visible="optSelectDialog.flag"
      @confirm="handleCloseSelect"
      @cancel="handleCloseSelect"
    >
      <div class="log-container" v-if="optSelectDialog.selects.length > 0">
        <div class="log-item select-item" v-for="(item, index) in optSelectDialog.selects" :key="index">
          <!-- {{ item.lineNumber }} {{ item.lineText }} -->
          <span class="log-item-num">{{ index + 1 }}</span>
          <!-- <p class="log-item-content">{{ item.lineText }}</p> -->
          <div class="select-item-container">
            <h4 class="select-item-event">{{ item.eventName }}</h4>
            <div class="select-item-opt">{{ item.optName }}</div>
          </div>
        </div>
      </div>
      <div class="log-empty" v-else>
        <i class="iconfont icon-wushuju1 data-empty-icon"></i>
        <h3 class="data-empty">暂无数据</h3>
      </div> 
    </Dialoger>
  </div>
</template>
<script setup>
import Condition from '@/components/common/Condition.vue';
import Pagination from '@/components/common/Pagination';
import Dialoger from '@/components/common/Dialoger.vue';
import * as algoApi from '@/api/algo.js';
import * as fileApi from '@/api/file.js';
import * as storage from '@/utils/storage'
import { useRouter } from 'vue-router';
import { ref, computed, onActivated, onDeactivated, onUnmounted, nextTick } from 'vue';
import { api } from '@/utils/status';
import { ElMessage, ElMessageBox } from 'element-plus';

let updateTimer = null;
// ============> data
// 为了解决element-plus中el-switch初始化调用change事件引入的变量
const isInit = ref(true);
const router = useRouter();
const systems = api.common.systems;
const taskStatus = api.algo.status;
// 搜索条件表单项
const conditionForm = ref({
  flag: false,
  loading: false,
  name: '',
  saveName: '',
  system: null,
  saveSystem: null,
  status: null,
  saveStatus: null,
  // 页条数
  pageSize: 10,
  // 当前页
  pageNumber: 1,
  // 总条数
  totalRow: 0,
  // 总页数
  totalPage: 0
});
const datas = ref([]);
// 日志弹框对象
const log = ref({
  flag: false,
  logId: '',
  logName: '',
  logLine: 1,
  logs: [],
  logSave: '',
  logReader: null
});
// 算法生成选取步骤弹框对象
const optSelectDialog = ref({
  flag: false,
  dialogName: '',
  dialogId: '',
  selects: []
});
// ============> computed
const getShow = computed(() => {
  return function (v, k, arr, returnKey) {
    let obj = arr.find((item) => item[k] === v);
    let res = obj ? obj[returnKey] : "--";
    return res;
  };
});
const startDisabled = computed(() => {
  return function (status){
    return status !== 0;
  }
});
const restartDisabled = computed(() => {
  return function (status){
    return status !== 3 && status !== 4;
  }
});
const downloadDisabled = computed(() => {
  return function (item, key){
    return item.status != 3 || !item[key];
  }
});


// ============> methods
function changeIsUsed(e, event){
  if (isInit.value){
    return;
  }
  algoApi.changeIsUsed({id: e.id})
    .then(res => {
      ElMessage.success('操作成功');
    })
    .catch(err => {
      console.log(err)
      e.isUsed = event === 0 ? 1 : 0;
    })
}
// 点击列表中项名称显示算法选择步骤弹框
function showSelect(row){
  console.log(row)
  if (row.optSelect && Array.isArray(row.optSelect) && row.optSelect.length > 0){
    optSelectDialog.value.dialogName = row.name;
    optSelectDialog.value.dialogId = row.id;
    optSelectDialog.value.selects = row.optSelect;
    optSelectDialog.value.flag = true;
  } else {
    ElMessage.warning('暂未提供算法生成过程的选项选择信息!');
  }
}
// 点击显示算法日志弹框建立sse连接
function showLog(row){
  async function connectSSEWithAxiosLike() {
    const response = await fetch(`${api.baseUrl}${algoApi.algoLogPath}?algoId=${row.id}&readLineNum=${log.value.logLine}`, {
      headers: {
        'Accept': 'text/event-stream',
        'content-type': 'text/event-stream',
        'Authorization': storage.getToken()
      },
    });
    if (!response.ok || !response.body) {
      throw new Error('SSE 连接失败');
    }
    log.value.logReader =  response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    log.value.logId = row.id;
    log.value.logName = row.name;
    log.value.flag = true;
    while(true){
      const { value, done } = await log.value.logReader.read();
      if (done) break;
      const data = decoder.decode(value, {stream: true});
      let result = data.split('\n\n');
      result.forEach(item => {
        if (item.startsWith('data:') && item.endsWith('}')) {
          deelItem(item)
        } else {
          let temp = log.value.logSave + item;
          if (temp.startsWith('data:') && temp.endsWith('}')){
            deelItem(temp)
          } else {
            log.value.logSave = item;
          }
        }
      })
    }
    function deelItem(json){
      let jsonObj = json.slice(5)
      jsonObj = JSON.parse(jsonObj)
      if (jsonObj.code === 200 && Array.isArray(jsonObj.data)) {
        log.value.logs.push(...jsonObj.data)
      } 
    }
  }
  connectSSEWithAxiosLike().catch(console.error);
}
// 点击弹框的关闭事件
function handleCloseLog(){
  log.value.flag = false;
  log.value.logs = [];
  log.value.logId = '';
  log.value.logName = '';
  log.value.logSave = '';
  log.value.logReader.cancel();
  log.value.logReader = null;
}
// 点击生成步骤的关闭事件
function handleCloseSelect(){
  optSelectDialog.value.flag = false;
  optSelectDialog.value.dialogName = '';
  optSelectDialog.value.dialogId = '';
  optSelectDialog.value.selects = [];
}
// 重置上方的搜索条件
function resetCondition(){
  conditionForm.value.name = conditionForm.value.name != conditionForm.value.saveName ? conditionForm.value.saveName : conditionForm.value.name;
  conditionForm.value.system = conditionForm.value.system != conditionForm.value.saveSystem ? conditionForm.value.saveSystem : conditionForm.value.system;
  conditionForm.value.status = conditionForm.value.status != conditionForm.value.saveStatus ? conditionForm.value.saveStatus : conditionForm.value.status;
}
// 设置上方的搜索条件
function setCondition(){
  conditionForm.value.saveName = conditionForm.value.name;
  conditionForm.value.saveSystem = conditionForm.value.system;
  conditionForm.value.saveStatus = conditionForm.value.status;
}
function getList(){
  if (conditionForm.value.flag){
    resetCondition();
    return;
  }
  conditionForm.value.loading = true;
  const { name, system, status, pageSize, pageNumber } = conditionForm.value;
  isInit.value = true;
  algoApi.getAlgoList({name, system, status, pageSize, pageNumber})
    .then(res => {
      datas.value = res.records && Array.isArray(res.records) ? res.records : [];
      initDatas();
      setCondition();
      conditionForm.value.pageNumber = +res.pageNumber;
      conditionForm.value.pageSize = +res.pageSize;
      conditionForm.value.totalRow = +res.totalRow;
      conditionForm.value.totalPage = +res.totalPage;
      conditionForm.value.loading= false;
      conditionForm.value.flag = false;
      nextTick(() => {
        isInit.value = false;
      })
    })
    .catch(err => {
      conditionForm.value.loading = false;
      conditionForm.value.flag = false;
      console.log(err)
      resetCondition();
    })
}
function initDatas(){
  if (Array.isArray(datas.value) && datas.value.length > 0){
    datas.value.forEach(item => {
      item.delFlag = false;
      item.execFlag = false;
      item.optSelect = []
    })
  }
}
// 执行/启动
function exec(item){
  if (item.execFlag){
    ElMessage.warning('当前正在启动，请稍后再试');
    return;
  }
  item.execFlag = true;
  algoApi.doingAlgo({ id: item.id})
    .then(res => {
      ElMessage.success('启动成功！');
      item.execFlag = false;
      getList();
    })
    .catch(err => {
      item.execFlag = false;
    })
}
function restart(item){
  algoApi.restartAlgo({ id: item.id })
    .then(res => {
      console.log(res);
      ElMessage.success('重启成功！');
      getList();
    })
    .catch(err => {
      console.log(err);
    })
}
function delItem(item){
  if (item.delFlag) {
    ElMessage.warning('当前算法正在删除，请稍后再试');
    return;
  }
  ElMessageBox.confirm('您是否确认删除此算法？', '警告', {
    confirmButtonText: '确定',
    cancelButtonText: '取消'
  })
    .then(() => {
      item.delFlag = true;
      algoApi.deleteAlgo({
        id: item.id
      })
        .then(res => {
          ElMessage.success('删除算法成功！');
          item.delFlag = false;
          getList();
        })
        .catch(err => {
          console.log(err);
          item.delFlag = false;
          // let msg = err.msg || err.message || '删除算法失败，请稍后重试或联系管理员';
          // ElMessage.error(msg);
        })
    })
    .catch(() => {})
}
function downloadRes(item, key){
  if (!item[key]){
    ElMessage.warning('未提供下载结果，请稍后重试或联系管理员!');
    return;
  }
  fileApi.download({ fileId: item[key]})
    .then(res => {
      let { fileName, fileUrl } = res;
      if (fileUrl){
        ElMessage.success('下载开始');
        let xhr = new XMLHttpRequest();
        xhr.open('get', fileUrl, true);
        xhr.send();
        xhr.responseType = 'blob';
        xhr.onload = function (){
          if (this.status >= 200 && this.status < 300 || this.status == 304) {
            let blob = new Blob([this.response]),
                a = document.createElement('a'),
                url = window.URL.createObjectURL(blob),
                filename = fileName;
            a.href = url;
            a.download = filename;
            a.click();
            window.URL.revokeObjectURL(url);
          } else {
            ElMessage.error('下载失败，请稍后重试或联系管理员！');
          }
        }
        xhr.onerror = function (e){
          ElMessage.error('下载请求失败，请稍后重试或联系管理员！');
        }
      } else {
        ElMessage.error('未提供下载链接，下载失败，请稍后重试或联系管理员！');
      }
    })
    .catch(err => {
      console.log('下载报错')
      console.log(err)
    })
}
// 分页触发事件
function pageChange(e){
  // { page, limit }
  conditionForm.value.pageSize = e.limit;
  conditionForm.value.pageNumber = e.page;
  getList();
}

function linkToCreate(){
  router.push({ name: 'algorithmCreate' });
}

// onMounted(() => {
//   getList();
// });

onActivated(() => {
  if (!updateTimer) {
    getList();
    updateTimer = setInterval(() => {
      getList();
    }, 5000);
  }
});

onDeactivated(() => {
  if (updateTimer){
    updateTimer = clearInterval(updateTimer);
  }
});

onUnmounted(() => {
  if (updateTimer){
    updateTimer = clearInterval(updateTimer);
  }
})
</script>
<style lang='scss' scoped>
@import '@/assets/styles/mixin.scss';
.table-actions {
  display: flex;
  align-items: center;
  justify-content: space-around;
  width: 100%;
  height: 100%;
  .action {
    width: 80px;
  }
}
.green {
  color: var(--color-green);
}
.red {
  color: var(--color-red);
  @include red-text-shadow;
}
.blue {
  color: var(--color-text-hover);
  @include blue-text-shadow;
}
.main-color {
  color: var(--color-main);
  @include main-text-shadow;
}
.table-actions-column {
  width: 100%;
  flex-direction: column;
  .actions-column {
    width: 100%;
    display: flex;
    justify-content: space-around;
  }
}
.text-btn {
  width: 100%;
}
.text-btn:hover {
  color: var(--color-main)
}
.text-btn::v-deep span {
  white-space: wrap;
  flex-wrap: wrap;

}
.log-item {
  width: 100%;
  display: flex;
  align-items: flex-start;
  margin-bottom: 4px;
}
.log-item.select-item {
  align-items: center;
}
.log-item-num {
  width: 40px;
  display: inline-block;
  color: var(--color-main-8);
}
.log-item-content {
  word-break: break-all;
  width: calc(100% - 30px);
  color: var(--color-main)
}
.select-item-container {
  width: calc(100% - 40px);
  border-radius: 4px;
  border: 2px solid var(--color-main);
  background-color: var(--color-white-10);
  text-align: center;
}
.select-item-event {
  color: var(--color-main);
}
.select-item-opt {
  width: 90%;
  margin: 6px auto; 
  border-radius: 4px;
  padding: 5px;
  background-color: var(--color-main);
  color: var(--color-white-10);
}
.log-empty {
  height: 40vh!important;
  @include flex-all-center;
  flex-direction: column;
      // background-color: var(--color-main-3);
      // 无数据提示语
      .data-empty {
        color: var(--color-main);
        font-size: 28px;
      }
      // 无数据图标
      .data-empty-icon {
        color: var(--color-main);
        font-size: 80px;
      }
}
.el-switch::v-deep .el-switch__core {
  border-radius: 4px;
}
.el-switch.is-checked::v-deep .el-switch__core {
  background-color: var(--color-main);
  border-color: var(--color-main);
}
.el-switch::v-deep .el-switch__core .el-switch__action {
  border-radius: 2px;
}
</style>